home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / TECHNICA / COMPUTER / H254.ZIP / IRITSM3S.ZIP / POLY3D-R / POLY3D-R.C < prev    next >
C/C++ Source or Header  |  1992-01-12  |  20KB  |  562 lines

  1. /*****************************************************************************
  2. *   Program to draw 3D object as solid objects in GIF image file format.     *
  3. *                                         *
  4. * Options:                                     *
  5. * 1. -a ambient : Ratio of the ambient color.                     *
  6. * 2. -c n : Number of bit ber pixel (2^n is number of colors possible).         *
  7. * 3. -l x y z : Light source direction vector.                     *
  8. * 4. -2 : Force 2 light sources at opposite direction of light vectors.      *
  9. * 5. -m : More flag, to print more imformation on input/errors.             *
  10. * 6. -s x y : Specify new dimensions to generate the resulting image.         *
  11. * 7. -S SubSample : specifies dimension of pixel sub sampling (1..4).         *
  12. * 8. -g : Use gouraud shading.                             *
  13. * 9. -b : Delete Back facing polygons.                         *
  14. * 10. -M Mask : Create boolean Mask (coverage) image as well.             *
  15. * 11. -z : Print current version, and some helpfull data.             *
  16. * 12. -f FineNess : log based 2 of the surface to polygons subdiv, fineness. *
  17. *                                         *
  18. * Note some of those options may be permanently set to a different default   *
  19. * using the configuration file "Poly3D-R.cfg"                     *
  20. *                                         *
  21. * Usage: poly3d-r [-a Ambient] [-c N] [-l X Y Z] [-2] [-m] [-s Xsize Ysize]  *
  22. *               [-S SubSample] [-g] [-b] [-M Mask] [-z] [-f FineNess] DFiles *
  23. *                                         *
  24. * Written by:  Gershon Elber                Ver 3.0, Aug 1990    *
  25. *****************************************************************************/
  26.  
  27. #ifdef __MSDOS__
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <conio.h>
  31. #include <io.h>
  32. #include <dos.h>
  33. #include <alloc.h>
  34. #endif /* __MSDOS__ */
  35. #include <stdio.h>
  36. #include <math.h>
  37. #include <time.h>
  38. #include "program.h"
  39. #include "getarg.h"
  40. #include "genmat.h"
  41. #include "iritprsr.h"
  42. #include "config.h"
  43.  
  44. #ifdef __TURBOC__      /* Malloc debug routine - only on TC++ 1.0 and above. */
  45. #define __DEBUG_MALLOC__
  46. #endif /* __TURBOC__ */
  47.  
  48. #ifdef __MSDOS__
  49. /* This huge stack is mainly from second phase - the segment intersections   */
  50. /* which may cause recursive calls - a lot...                     */
  51. extern unsigned int _stklen = 32766;
  52. #endif /* __MSDOS__ */
  53.  
  54. #ifdef NO_CONCAT_STR
  55. static char *VersionStr =
  56.     "Poly3D-R    Version 3.0,    Gershon Elber,\n\
  57.     (C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
  58. #else
  59. static char *VersionStr = "Poly3D-R    " VERSION ",    Gershon Elber,    "
  60.     __DATE__ ",  " __TIME__ "\n"
  61.     "(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
  62. #endif /* NO_CONCAT_STR */
  63.  
  64. static char *CtrlStr =
  65. #ifdef __MSDOS__
  66.     "poly3d-r a%-Ambient!f c%-N!d l%-X|Y|Z!f!f!f 2%- m%- s%-Xsize|Ysize!d!d S%-SubSample!d g%- b%- M%-Mask!s z%- f%-FineNess!d DFiles!*s";
  67. #else
  68.     "poly3d-r a%-Ambient!F c%-N!d l%-X|Y|Z!F!F!F 2%- m%- s%-Xsize|Ysize!d!d S%-SubSample!d g%- b%- M%-Mask!s z%- f%-FineNess!d DFiles!*s";
  69. #endif /* __MSDOS__ */
  70.  
  71. static long SaveTotalTime;
  72. static GifColorType MaskColorMap[2] = {     /* Boolean mask GIF file color map. */
  73.     {   0,   0,   0 },
  74.     { 255, 255, 255 }
  75. };
  76. /* Fineness surface subdivision control. */
  77. static int GlblFineNess = DEFAULT_FINENESS;
  78.  
  79. int GlblNumOfPolys = 0;         /* Total number of polygons scan converted. */
  80. int GlblNumOfVerts = 0;                /* Total number of vertices. */
  81. MatrixType GlblViewMat;                  /* Current view of object. */
  82.  
  83. /* Amount scene was scaled up from normalized [-1..1] size on both X & Y: */
  84. RealType GlblScaleUpFctr = 0.0;
  85.  
  86. /* The following are setable variables (via configuration file poly3d-h.cfg).*/
  87. int GlblMore = FALSE;
  88.  
  89. ShadeInfoStruct GlblShadeInfo = {
  90.     1,                           /* Sub samples per pixel. */
  91.     DEFAULT_BITS_PER_PIXEL,
  92.     0,
  93.     DEFAULT_COLOR,
  94.     DEFAULT_BACK_GROUND_COLOR,
  95.     FALSE,                        /* No two light sources. */
  96.     DEFAULT_SCREEN_XSIZE,
  97.     DEFAULT_SCREEN_YSIZE,
  98.     FALSE,                          /* No Gouraud shading. */
  99.     FALSE,                      /* No back facing deletion. */
  100.     NULL,
  101.     NULL,                        /* No color map yet. */
  102.     DEFAULT_LIGHT_SOURCE,
  103.     DEFAULT_AMBIENT,
  104.     DEFAULT_NORMAL_AVG_DEGREE
  105. };
  106.  
  107. static ConfigStruct SetUp[] = {
  108.   { "Ambient",        (VoidPtr) &GlblShadeInfo.Ambient,    SU_REAL_TYPE },
  109.   { "LightSrcX",    (VoidPtr) &GlblShadeInfo.LightSource[0],SU_REAL_TYPE },
  110.   { "LightSrcY",    (VoidPtr) &GlblShadeInfo.LightSource[1],SU_REAL_TYPE },
  111.   { "LightSrcZ",    (VoidPtr) &GlblShadeInfo.LightSource[2],SU_REAL_TYPE },
  112.   { "AvgDegree",    (VoidPtr) &GlblShadeInfo.NrmlAvgDegree,    SU_REAL_TYPE },
  113.   { "TwoSources",    (VoidPtr) &GlblShadeInfo.TwoSources,    SU_BOOLEAN_TYPE },
  114.   { "Gouraud",        (VoidPtr) &GlblShadeInfo.Gouraud,    SU_BOOLEAN_TYPE },
  115.   { "backFacing",    (VoidPtr) &GlblShadeInfo.BackFacing,    SU_BOOLEAN_TYPE },
  116.   { "SubSample",    (VoidPtr) &GlblShadeInfo.SubSamplePixel,SU_INTEGER_TYPE },
  117.   { "BitsPerPixel",    (VoidPtr) &GlblShadeInfo.BitsPerPixel,    SU_INTEGER_TYPE },
  118.   { "Color",        (VoidPtr) &GlblShadeInfo.DefaultColor,    SU_INTEGER_TYPE },
  119.   { "BackGroundColor",    (VoidPtr) &GlblShadeInfo.BackGroundColor,SU_INTEGER_TYPE },
  120.   { "Xsize",        (VoidPtr) &GlblShadeInfo.ScrnXSize,    SU_INTEGER_TYPE },
  121.   { "Ysize",        (VoidPtr) &GlblShadeInfo.ScrnYSize,    SU_INTEGER_TYPE },
  122.   { "FineNess",        (VoidPtr) &GlblFineNess,        SU_INTEGER_TYPE },
  123.   { "More",        (VoidPtr) &GlblMore,            SU_BOOLEAN_TYPE }
  124. };
  125. #define NUM_SET_UP    (sizeof(SetUp) / sizeof(ConfigStruct))
  126.  
  127. /* All polygons to be scan convert will be inserted into this hash table     */
  128. /* during the preprocessing (PrepareXXXX functions).                 */
  129. IPPolygonStruct **PolyHashTable;
  130.  
  131.  
  132. static IPObjectStruct *MainGetDataFiles(char **DataFileNames, int NumOfDataFiles);
  133. static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf);
  134.  
  135. /*****************************************************************************
  136. * Main routine - Read Parameter    line and do what you need...             *
  137. *****************************************************************************/
  138. void
  139. #ifdef __MSDOS__
  140. cdecl        /* So we can use -rp in Borland 3.0 (parameters in registers.). */
  141. #endif /* __MSDOS__ */
  142. main(int argc, char **argv)
  143. {
  144.     int AmbientFlag = FALSE,
  145.     ColorFlag = FALSE,
  146.     LightSrcFlag = FALSE,
  147.     GifMaskFlag = FALSE,
  148.     VerFlag = FALSE,
  149.     NumFiles = 0,
  150.     ImageSizeFlag = FALSE,
  151.     SubSampleFlag = FALSE,
  152.     FineNessFlag = FALSE,
  153.     Error;
  154.     char *GifMaskName,
  155.     **FileNames = NULL;
  156.     RealType Size, Scale;
  157.     MatrixType Mat;
  158.     IPObjectStruct *PObjects;
  159.     GifFileType *GifFile,
  160.     *GifMask = NULL;
  161.  
  162.     SaveTotalTime = time(NULL);                  /* Save starting time. */
  163. #ifdef __MSDOS__
  164.     ctrlbrk((int cdecl (*)()) MyExit);           /* Kill this program if ^C... */
  165. #endif /* __MSDOS__ */
  166.  
  167.     Config("poly3d-r", SetUp, NUM_SET_UP);   /* Read config. file if exists. */
  168.  
  169.     if ((Error = GAGetArgs (argc, argv, CtrlStr,
  170.         &AmbientFlag, &GlblShadeInfo.Ambient,
  171.         &ColorFlag, &GlblShadeInfo.BitsPerPixel, &LightSrcFlag,
  172.         &GlblShadeInfo.LightSource[0],
  173.         &GlblShadeInfo.LightSource[1],
  174.         &GlblShadeInfo.LightSource[2],
  175.         &GlblShadeInfo.TwoSources, &GlblMore, &ImageSizeFlag,
  176.         &GlblShadeInfo.ScrnXSize, &GlblShadeInfo.ScrnYSize,
  177.         &SubSampleFlag, &GlblShadeInfo.SubSamplePixel,
  178.         &GlblShadeInfo.Gouraud, &GlblShadeInfo.BackFacing,
  179.         &GifMaskFlag, &GifMaskName,
  180.         &VerFlag, &FineNessFlag, &GlblFineNess,
  181.         &NumFiles, &FileNames)) != 0) {
  182.     GAPrintErrMsg(Error);
  183.     GAPrintHowTo(CtrlStr);
  184.     MyExit(1);
  185.     }
  186.  
  187.     if (GlblShadeInfo.Ambient < 0.0 || GlblShadeInfo.Ambient > 1.0) {
  188.     fprintf(stderr,
  189.             "Ambient light specified not in [0.0..1.0] range, %lf selected instead.\n",
  190.         DEFAULT_AMBIENT);
  191.     GlblShadeInfo.Ambient = DEFAULT_AMBIENT;
  192.     }
  193.     if (GlblShadeInfo.BitsPerPixel < 1 || GlblShadeInfo.BitsPerPixel > 8) {
  194.     fprintf(stderr,
  195.             "PitsPerPixel not in [1..8] range, %d selected instead.\n",
  196.         DEFAULT_BITS_PER_PIXEL);
  197.     GlblShadeInfo.BitsPerPixel = DEFAULT_BITS_PER_PIXEL;
  198.     }
  199.  
  200.     Size = sqrt(SQR(GlblShadeInfo.LightSource[0]) +
  201.         SQR(GlblShadeInfo.LightSource[1]) +
  202.         SQR(GlblShadeInfo.LightSource[2]));
  203.     if (ABS(Size) < EPSILON) {
  204.     fprintf(stderr, "Light source vector is zero, Z axis selected instead.\n");
  205.     GlblShadeInfo.LightSource[0] =
  206.     GlblShadeInfo.LightSource[1] = 0.0;
  207.     GlblShadeInfo.LightSource[2] = 1.0;
  208.     }
  209.     else {
  210.     GlblShadeInfo.LightSource[0] /= Size;
  211.     GlblShadeInfo.LightSource[1] /= Size;
  212.     GlblShadeInfo.LightSource[2] /= Size;
  213.     }
  214.  
  215.     if (VerFlag) {
  216.     fprintf(stderr, "\n%s\n\n", VersionStr);
  217.     GAPrintHowTo(CtrlStr);
  218.     ConfigPrint(SetUp, NUM_SET_UP);
  219.     MyExit(0);
  220.     }
  221.  
  222.     if (!NumFiles) {
  223.     fprintf(stderr, "No data file names were given, exit.\n");
  224.     GAPrintHowTo(CtrlStr);
  225.     MyExit(1);
  226.     }
  227.  
  228.     if (SubSampleFlag) {
  229.     if (GlblShadeInfo.SubSamplePixel < 1 || GlblShadeInfo.SubSamplePixel > 4) {
  230.         fprintf(stderr, "Sub sampling can be 1 to 4 only (1x1 to 4x4).\n");
  231.         GAPrintHowTo(CtrlStr);
  232.         MyExit(1);
  233.     }
  234.     }
  235.  
  236.     /* Get the data files: */
  237.     IritPrsrPolyListCirc = FALSE;
  238.     PObjects = MainGetDataFiles(FileNames, NumFiles);
  239.  
  240.     /* Compute the viewing matrices and related data: */
  241.     if (IritPrsrWasPrspMat)
  242.     MultTwo4by4(GlblViewMat, IritPrsrViewMat, IritPrsrPrspMat);
  243.     else
  244.     GEN_COPY(GlblViewMat, IritPrsrViewMat, sizeof(MatrixType));
  245.  
  246.     /* Now its time to scale the normalized image (+/-1 on both X & Y) to    */
  247.     /* size specified by the image dimensions. We scale up to the SMALLER    */
  248.     /* dimension, and put the center at the image center.             */
  249.     /* Also, as the GIF image starts at the top, we must flip the image      */
  250.     /* along Y axis.                                 */
  251.     GlblScaleUpFctr = Scale = MIN(GlblShadeInfo.ScrnXSize *
  252.                   GlblShadeInfo.SubSamplePixel,
  253.                   GlblShadeInfo.ScrnYSize *
  254.                   GlblShadeInfo.SubSamplePixel) / 2.0;
  255.     GenMatScale(Scale, -Scale, Scale, Mat);
  256.     MultTwo4by4(GlblViewMat, GlblViewMat, Mat);
  257.     GenMatTrans(GlblShadeInfo.ScrnXSize * GlblShadeInfo.SubSamplePixel / 2.0,
  258.         GlblShadeInfo.ScrnYSize * GlblShadeInfo.SubSamplePixel / 2.0,
  259.         0.0, Mat);
  260.     MultTwo4by4(GlblViewMat, GlblViewMat, Mat);
  261.  
  262.     /* Prepare data structures of objects themselves: */
  263.     PrepareViewData(PObjects);
  264.  
  265.     /* Into shadingInfo global structure: */
  266.     PrepareColorTable(PObjects);
  267.  
  268.     EvalVrtxColors(PObjects);
  269.  
  270. #ifndef DEBUG_NO_GIF
  271.  
  272.     /* Open stdout for the GIF image file: */
  273.     if ((GifFile = EGifOpenFileHandle(1)) == NULL ||
  274.     EGifPutScreenDesc(GifFile,
  275.         GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
  276.         GlblShadeInfo.BitsPerPixel, 0,
  277.         GlblShadeInfo.BitsPerPixel, GlblShadeInfo.PColorMap) ==
  278.                                 GIF_ERROR ||
  279.     EGifPutImageDesc(GifFile,
  280.         0, 0, GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize, FALSE,
  281.         GlblShadeInfo.BitsPerPixel, NULL) == GIF_ERROR)
  282.     QuitGifError();
  283.     /* Open special mask file if required: */
  284.     if (GifMaskFlag &&
  285.     ((GifMask = EGifOpenFileName(GifMaskName, FALSE)) == NULL ||
  286.      EGifPutScreenDesc(GifMask,
  287.                GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
  288.                1, 0, 1, MaskColorMap) == GIF_ERROR ||
  289.      EGifPutImageDesc(GifMask, 0, 0,
  290.               GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
  291.               FALSE, 1, NULL) == GIF_ERROR))
  292.     QuitGifError();
  293.  
  294. #endif /* DEBUG_NO_GIF */
  295.  
  296.     ScanConvertData(GifFile, GifMask);     /* Do the real interesting stuff... */
  297.  
  298. #ifndef DEBUG_NO_GIF
  299.  
  300.     EGifCloseFile(GifFile);
  301.     if (GifMask) EGifCloseFile(GifMask);
  302.  
  303. #endif /* DEBUG_NO_GIF */
  304.  
  305.     MyExit(0);
  306. }
  307.  
  308. /*****************************************************************************
  309. * Main routine to read the data    description files:                 *
  310. * Returns pointer to pointers on FileDescription structures (one per file).  *
  311. *****************************************************************************/
  312. static IPObjectStruct *MainGetDataFiles(char **DataFileNames, int NumOfDataFiles)
  313. {
  314.     int    i;
  315.     char *ErrorMsg;
  316.     FILE *f;
  317.     long
  318.     SaveTime = time(NULL);
  319.     IPObjectStruct *PObj, *PObjTail,
  320.     *PObjHead = NULL;
  321.  
  322.     fprintf(stderr, "Reading data file(s).\n");
  323.  
  324.     for    (i = 0; i < NumOfDataFiles; i++) {
  325.     if (GlblMore) fprintf(stderr, "Reading %s.\n", *DataFileNames);
  326.  
  327. #ifdef __MSDOS__
  328.     if ((f = fopen(*DataFileNames, "rt")) == NULL) {   /* Open the file. */
  329. #else
  330.     if ((f = fopen(*DataFileNames, "r")) == NULL) {    /* Open the file. */
  331. #endif /* __MSDOS__ */
  332.         fprintf(stderr, "Can't open data file %s.\n", *DataFileNames);
  333.         MyExit(1);
  334.     }
  335.  
  336.     if ((PObj = IritPrsrGetObjects(f)) != NULL) {  /* Get the data file. */
  337.         PObjTail = PObj;
  338.         while (PObjTail -> Pnext) PObjTail = PObjTail -> Pnext;
  339.         PObjTail -> Pnext = PObjHead;
  340.         PObjHead = PObj;
  341.     }
  342.  
  343.     if (GlblMore && IritPrsrParseError(&ErrorMsg))
  344.         fprintf(stderr, "File %s, %s\n", *DataFileNames, ErrorMsg);
  345.  
  346.     fclose(f);                      /* Close the file. */
  347.  
  348.     DataFileNames++;              /* Skip to next file name. */
  349.     }
  350.  
  351.     if (PObjHead == NULL) {
  352.     fprintf(stderr, "No data found.\n");
  353.     MyExit(1);
  354.     }
  355.  
  356.     fprintf(stderr, "Done reading,  %ld seconds.", time(NULL) - SaveTime);
  357.  
  358.     return PObjHead;
  359. }
  360.  
  361. /*****************************************************************************
  362. * Routine to convert all surfaces/curves into polylines as follows:         *
  363. * Curves are converted to single polyline with SamplesPerCurve samples.         *
  364. * Surface are converted into GlblNumOfIsolines curves in each axes, each     *
  365. * handled as Curves above. The curves and surfaces are then deleted.         *
  366. *****************************************************************************/
  367. IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs,
  368.                     IPObjectStruct *SrfObjs)
  369. {
  370.     CagdCrvStruct *Crvs;
  371.     CagdSrfStruct *Srf, *Srfs;
  372.     IPObjectStruct *PObj, *PObjNext;
  373.     IPPolygonStruct *PPolygon, *PPolygonTemp;
  374.  
  375.     if (CrvObjs == NULL && SrfObjs == NULL) return NULL;
  376.  
  377.     /* Make sure requested format is something reasonable. */
  378.     if (GlblFineNess < 2) {
  379.     GlblFineNess = 2;
  380.     if (GlblMore)
  381.         fprintf(stderr, "FineNess is less than 2, 2 picked instead.\n");
  382.     }
  383.  
  384.     if (CrvObjs) {
  385.     /* Curves are not rendered at this time and they are ignored. */
  386.     for (PObj = CrvObjs; PObj != NULL;) {
  387.         Crvs = PObj -> U.PCrvs;
  388.         CagdCrvFreeList(Crvs);
  389.         PObjNext = PObj -> Pnext;
  390.         free(PObj);
  391.         PObj = PObjNext;
  392.     }
  393.     CrvObjs = NULL;
  394.     }
  395.  
  396.     if (SrfObjs) {
  397.     for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
  398.         Srfs = PObj -> U.PSrfs;
  399.         PObj -> U.PPolygon = NULL;
  400.         for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
  401.         PPolygon = PPolygonTemp = Surface2Polygons(Srf);
  402.         while (PPolygonTemp -> Pnext)
  403.             PPolygonTemp = PPolygonTemp -> Pnext;
  404.         PPolygonTemp -> Pnext = PObj -> U.PPolygon;
  405.         PObj -> U.PPolygon = PPolygon;
  406.         }
  407.         CagdSrfFreeList(Srfs);
  408.     }
  409.     }
  410.  
  411.     return SrfObjs;
  412. }
  413.  
  414. /*****************************************************************************
  415. * Routine to convert a single surface into a polygons with GlblFineNess      *
  416. * samples as the subdivision fineness measure.                     *
  417. *****************************************************************************/
  418. static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf)
  419. {
  420.     int i, j;
  421.     IPVertexStruct *V, *VHead;
  422.     IPPolygonStruct *P,
  423.     *PHead = NULL;
  424.     CagdPolygonStruct *CagdPolygon,
  425.     *CagdPolygonHead = NULL;
  426.  
  427.     CagdPolygonHead = CagdSrf2Polygons(Srf, 1 << GlblFineNess, TRUE, TRUE);
  428.  
  429.     for (CagdPolygon = CagdPolygonHead;
  430.      CagdPolygon != NULL;
  431.      CagdPolygon = CagdPolygon -> Pnext) {
  432.     /* All polygons are triangles! */
  433.  
  434.     for (i = 0, VHead = NULL; i < 3; i++) {         /* Convert to vertices. */
  435.         if (VHead == NULL)
  436.         VHead = V = IritPrsrNewVertexStruct();
  437.         else {
  438.         V -> Pnext = IritPrsrNewVertexStruct();
  439.         V = V -> Pnext;
  440.         }
  441.         IP_SET_VRTX_NORMAL(V);               /* Vertex has normal. */
  442.  
  443.         for (j = 0; j < 3; j++)                /* Convert to our format. */
  444.            V -> Coord[j] = CagdPolygon -> Polygon[i].Pt[j];
  445.         for (j = 0; j < 3; j++)
  446.            V -> Normal[j] = CagdPolygon -> Normal[i].Vec[j];
  447.  
  448.     }
  449.  
  450.     P = IritPrsrNewPolygonStruct();
  451.     P -> PVertex = VHead;
  452.     P -> Type = IP_POLYGON;
  453.     P -> Pnext = PHead;
  454.  
  455.     PHead = P;
  456.     }
  457.  
  458.     CagdPolygonFreeList(CagdPolygonHead);
  459.  
  460.     return PHead;
  461. }
  462.  
  463. #ifdef __DEBUG_MALLOC__
  464. /*****************************************************************************
  465. * My Routine to    allocate dynamic memory. All program requests must call this *
  466. * routine (no direct call to malloc). Dies if no memory.             *
  467. *****************************************************************************/
  468. static void AllocError(const char *Msg, VoidPtr *p)
  469. {
  470.     fprintf(stderr, "%s, Ptr = %p\n", Msg, p);
  471.     MyExit(3);
  472. }
  473. #endif /* __DEBUG_MALLOC__ */
  474.  
  475. /*****************************************************************************
  476. * My Routine to    allocate dynamic memory. All program requests must call this *
  477. * routine (no direct call to malloc). Dies if no memory.             *
  478. *****************************************************************************/
  479. VoidPtr MyMalloc(unsigned size)
  480. {
  481.     VoidPtr p;
  482.  
  483.     if ((p = malloc(size)) != NULL) return p;
  484.  
  485.     fprintf(stderr, "Not enough memory, exit.\n");
  486.     MyExit(2);
  487.  
  488.     return NULL;                    /* Make warnings silent. */
  489. }
  490.  
  491. /*****************************************************************************
  492. * My Routine to    free dynamic memory. All program requests must call this     *
  493. * routine (no direct call to free).                         *
  494. *****************************************************************************/
  495. void MyFree(VoidPtr p)
  496. {
  497. #ifdef __DEBUG_MALLOC__
  498.     switch (heapchecknode(p)) {
  499.     case _HEAPCORRUPT:
  500.         AllocError("Heap is corrupted", p);
  501.         break;
  502.     case _BADNODE:
  503.         AllocError("Attempt to free a bogus pointer", p);
  504.         break;
  505.     case _FREEENTRY:
  506.         AllocError("Attempt to free an already freed pointer", p);
  507.         break;
  508.     case _USEDENTRY:
  509.         break;
  510.     default:
  511.         AllocError("Allocation error", p);
  512.         break;
  513.  
  514.     }
  515. #endif /* __DEBUG_MALLOC__ */
  516.  
  517.     free(p);
  518. }
  519.  
  520. /*****************************************************************************
  521. * Trap Cagd_lib errors right here.                         *
  522. *****************************************************************************/
  523. void CagdFatalError(CagdFatalErrorType ErrID)
  524. {
  525.     char
  526.     *ErrorMsg = CagdDescribeError(ErrID);
  527.  
  528.     fprintf(stderr, "CAGD_LIB: %s", ErrorMsg);
  529.  
  530.     exit(-1);
  531. }
  532.  
  533. /*****************************************************************************
  534. * MyExit routine. Note it might call to CloseGraph without calling         *
  535. * InitGraph(), or call MouseClose() without MouseInit(), or call         *
  536. * RestoreCtrlBrk() without SetUpCtrlBrk() and it is the responsibility         *
  537. * of the individual modules to do nothing in these cases.             *
  538. *****************************************************************************/
  539. void MyExit(int ExitCode)
  540. {
  541. #ifdef __MSDOS__
  542.     fprintf(stderr,
  543.     "\nPoly3D-R: Total RealTime %ld seconds, Core left %ldk.\n",
  544.         time(NULL) - SaveTotalTime, coreleft() / 1024);
  545. #else
  546.     fprintf(stderr,
  547.     "\nPoly3D-R: Total RealTime %ld seconds.\n",
  548.         time(NULL) - SaveTotalTime);
  549. #endif /* __MSDOS__ */
  550.  
  551.     exit(ExitCode);
  552. }
  553.  
  554. /******************************************************************************
  555. * Close output file (if open), and exit.                      *
  556. ******************************************************************************/
  557. void QuitGifError(void)
  558. {
  559.     PrintGifError();
  560.     MyExit('G');
  561. }
  562.